<html>
<head>
  <title>17.中介者（Mediator）模式</title>
  <basefont face="微软雅黑" size="2" />
  <meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
  <meta name="exporter-version" content="YXBJ Windows/602628 (zh-CN, DDL); Windows/10.0.0 (Win64); EDAMVersion=V2;"/>
  <style>
    body, td {
      font-family: 微软雅黑;
      font-size: 10pt;
    }
  </style>
</head>
<body>
<a name="25243"/>
<h1>17.中介者（Mediator）模式</h1>
<div>
<table bgcolor="#D4DDE5" border="0">
<tr><td><b>创建时间：</b></td><td><i>2020/9/6 5:24</i></td></tr>
<tr><td><b>更新时间：</b></td><td><i>2021/3/11 0:21</i></td></tr>
<tr><td><b>作者：</b></td><td><i>Long Life Student</i></td></tr>
<tr><td><b>来源：</b></td><td><a href="https://github.com/PhycheLiu/DesignPattern_Study-Test"><i>https://github.com/PhycheLiu/DesignPattern_Study-Test</i></a></td></tr>
</table>
</div>
<br/>

<div>
<span><div><div><span style="font-weight: bold;">一、基本描述</span></div><ul><li><div>用一个中介对象来封装一系列的对象交互，中介者使各对象不需要显式的相互引用，从而使其耦合松散，而且可以独立的改变它们之间的交互。</div></li><li><div>面向对象设计鼓励将行为分布到各个对象中，这种分布可能会导致对象间有许多连接。在最坏的情况下，每一个对象都知道其他所有对象。虽然将一个系统分割成许多对象通常可以增强可复用性，但是对象间相互连接的激增又会降低其可复用性。大量的相互连接使得一个对象似乎不太可能在没有其他对象的支持下工作——系统表现为一个不可分割的整体。对系统的行为进行较大的改动都十分困难，因为行为被分布在许多对象中，结果是，可能不得不定义很多子类以定制系统的行为。（通过增加子类来新增、修改功能）</div></li><li><div>可以通过将集体行为封装在一个单独的中介者对象中来避免这个问题。中介者负责控制和协调一组对象间的交互。中介者充当一个中介以使组中的对象不再相互显式引用。这些对象仅知道中介者，从而减少了相互连接的数目。</div></li><li><div>下列情况下可以考虑使用中介者模式：</div></li></ul><div style="margin-left: 40px;">1）一组对象以定义良好但复杂的方式进行通信，产生的相互依赖关系结构混乱且难以理解。</div><div style="margin-left: 40px;">2）一个对象引用其他很多对象并且直接与这些对象通信，导致难以复用该对象。</div><div style="margin-left: 40px;">3）想定制一个分布在多个类中的行为，而又不想生成太多的子类。</div><div style="margin-left: 40px;">4）多个对象有依赖关系， 但是依赖的行为尚不确定或者有发生改变的可能， 在这种情况<span style="font-size: unset; color: unset; font-family: unset;">下一般建议采用中介者模式， 降低变更引起的风险扩散。</span></div><div style="margin-left: 40px;"><span style="font-size: unset; color: unset; font-family: unset;">5）</span>产品开发。 一个明显的例子就是MVC框架， 把中介者模式应用到产品中， 可以提升产<span style="font-size: unset; color: unset; font-family: unset;">品的性能和扩展性， 但是对于项目开发就未必， 因为项目是以交付投产为目标， 而产品则是</span><span style="font-size: unset; color: unset; font-family: unset;">以稳定、 高效、 扩展为宗旨。</span></div><ul><li><div>可以有两种方法实现同事类与中介者类之间的通信：</div></li></ul><div style="margin-left: 40px;">1）使用观察者模式。将Mediator实现为一个Observer，各Colleague作为Subject，一旦其状态改变就发送通知给Mediator，Mediator做出的响应是将状态改变的结果传播给其他的Colleague。（正宗的SOA）</div><div style="margin-left: 40px;">2）在Mediator中定义一个特殊的通知接口，各Colleague在通信时直接调用该接口。</div><ul><li><div>中介者模式又叫做调停者模式，是中间人或调停者的意思。</div></li><li><div>中介者模式主要应用“迪米特法则”：如果两个类不必彼此直接通信，那么这两个类就不应当发生直接的相互作用，如果其中的一个类需要调用另一个类的某一个方法时，可以通过第三者转发这个调用。中介者模式是“迪米特法则”的一个典型应用。</div></li><li><div>通过中介者对象，可以将系统的网状结构变为以中介者为中心的星型结构，每个具体对象不再通过直接的联系与另一个对象发生作用，二是通过“中介者”对象与另一个对象发生互相作用。</div></li><li><div>中介者对象的设计，使得系统的结构不会因为新的对象的引入造成大量的修改工作。</div></li><li><div>根据未来是否有可能扩展中介者对象，可以考虑Mediator和ConcreteMediator是否合二为一，如果不存在扩展的情况，二者可以合并。</div></li><li><div>中介者模式很容易在系统中应用，也很容易在系统中误用。当系统出现了“多对多”交互复杂的对象群时，不要急于使用中介者模式，而要反思你的系统在设计上是否合理。</div></li><li><div>中介者模式的优点来自集中控制，其缺点也是集中控制。</div></li><li><div>在实际项目中，<span style="font-size: unset; color: unset; font-family: unset;">一般的做法是中介者按照职责进行划分， 每个中介者处理一个或多个类似的关联请求。</span></div></li><li><div>同事类一般使用构造函数注入中介者， 而中介者一般使用getter/setter方式注入同事类，<span style="font-size: unset; color: unset; font-family: unset;"> 这是因为同事类必须有中介者， 而中介者却可以只有部分同事类。</span></div></li><li><div>中介者模式简单， 但是简单不代表容易使用， 很容易被误用。 在面向对象的编程中， 对<span style="font-size: unset; color: unset; font-family: unset;">象和对象之间必然会有依赖关系，</span>类之间的依赖关系是必然存在的， 一个类依赖多个类的情况也是存在的。并不是只要有多个依赖关系就考虑使用中介者模式。如原本就简单的几个对象依赖关系， 如果为了使用模式而加入了中介<span style="font-size: unset; color: unset; font-family: unset;">者， 必然导致中介者的逻辑复杂化， 因此中介者模式的使用需要“量力而行”。 中介者模式适</span><span style="font-size: unset; color: unset; font-family: unset;">用于多个对象之间紧密耦合的情况， 紧密耦合的标准是： 在类图中出现了蜘蛛网状结构。 在</span><span style="font-size: unset; color: unset; font-family: unset;">这种情况下一定要考虑使用中介者模式， 这有利于把蜘蛛网梳理为星型结构， 使原本复杂混</span><span style="font-size: unset; color: unset; font-family: unset;">乱的关系变得清晰简单。</span></div></li><li><div>MVC框架， 其中的C（Controller） 就是一个中介者， 叫做前端<span style="font-size: unset; color: unset; font-family: unset;">控制器(Front Controller)， 它的作用就是把M(Model， 业务逻辑)和V（View， 视图） 隔离开，</span><span style="font-size: unset; color: unset; font-family: unset;">协调M和V协同工作， 把M运行的结果和V代表的视图融合成一个前端可以展示的页面， 减少</span><span style="font-size: unset; color: unset; font-family: unset;">M和V的依赖关系。</span></div></li><li><div>中介者对象的存在保证了对象结构上的稳定，也即系统的结构不会因为新对象的引入带来大量的修改工作。</div></li><li><div>中介者模式的核心在于中介者类的引入，在中介者模式中，中介者类承担了两方面的职责：</div></li></ul><div style="margin-left: 40px;">1）中转作用（ 结构性） ： 通过中介者提供的中转作用， 各个同事对象就不再需要显式引用其<span style="font-size: unset; color: unset; font-family: unset;">他同事， 当需要和其他同事进行通信时， 可通过中介者来实现间接调用。 该中转作用属于中</span><span style="font-size: unset; color: unset; font-family: unset;">介者在结构上的支持。</span></div><div style="margin-left: 40px;"><span style="font-size: unset; color: unset; font-family: unset;">2）</span>协调作用（ 行为性） ： 中介者可以更进一步的对同事之间的关系进<span style="font-size: unset; color: unset; font-family: unset;">行封装， 同事可以一致的和中介者进行交互， 而不需要指明中介者需要具体怎么做， 中介者</span><span style="font-size: unset; color: unset; font-family: unset;">根据封装在自身内部的协调逻辑， 对同事的请求进行进一步处理， 将同事成员之间的关系行</span><span style="font-size: unset; color: unset; font-family: unset;">为进行分离和封装。 该协调作用属于中介者在行为上的支持。</span></div><ul><li><div>当需要新增具体同事时，可以选择修改具体中介者类，也可以再次继承抽象中借着类（或继承原有具体中介者类），并覆盖其中定义的方法（即另外做一个新的具体中介者）。</div></li><li><div>中介者<span style="font-size: unset; color: unset; font-family: unset;">模式在事件驱动类软件中应用较为广泛， 特别是基于GUI（ Graphical User Interface， 图形用户</span><span style="font-size: unset; color: unset; font-family: unset;">界面） 的应用软件。</span></div></li><li><div>使用中介者模式来集中相关对象之间复杂的沟通和控制方式。</div></li><li><div>在需要持续追踪每个对象的每个规则，以及众多对象之间彼此错综复杂的关系的系统中，加入一个中介者，一切都变得简单了：</div></li><ul><li><div>每个对象都会在自己的状态改变时，告诉中介者。</div></li><li><div>每个对象都会对中介者所发出的请求作出回应。</div></li></ul></ul><div><span style="font-weight: bold;">二、图例</span></div><div><img src="17.中介者（Mediator）模式_files/Image.png" type="image/png" data-filename="Image.png" width="649"/></div><ul><li><div><span style="font-weight: bold;">Mediator（中介者）：</span>中介者定义一个接口用于与各同事对象通信。当各Colleague仅与一个Mediator一起工作时，没有必要定义一个抽象的Mediator类。</div></li><li><div><span style="font-weight: bold;">ConcreteMediator（具体中介者）：</span>具体中介者通过协调各同事对象实现协作行为。了解并维护它的各个同事。必须依赖于各个同事角色，维护对各个同事对象的引用。实现抽象类Mediator的方法，从具体同事类接收消息，向具体同事对象发出命令。将调用同事类的方法，调用时可以增加一些自己的业务代码，将调用进行控制。</div></li><li><div><span style="font-weight: bold;">Colleague（抽象同事）：</span>定义各个同事类公有的方法，同时维护一个对抽象中介者类的引用，其子类可以通过该引用来与中介者通信。</div></li><li><div><span style="font-weight: bold;">ConcreteColleague（具体同事）：</span>每一个同事类都知道它的中介者对象。每一个同事类对象在需要与其他同事通信的时候，与它的中介者通信。每个同事类的行为分为两种，一种是同事本身的行为，如该表对象本身的状态，处理自己的行为等，与其他同事类或中介者没有任何依赖，这种行为叫做自发行为（Self-Method），另一种是必须依赖中介者才能完成的行为，叫做依赖方法（DepMethod）。每一个具体同事类只知道自己的行为，而不了解其他同事类的情况，但他们却都认识中介者对象。每一个同事对象在需要和其他同事对象通信的时候，先与中介者通信，通过中介者来简介完成与其他同事类的通信，同时，实现了抽象同事类中声明的抽象方法。</div></li><li><div><span style="font-weight: bold;">协作：</span>同事向一个中介者对象发送和接收请求，中介者在各同事间适当的转发请求以实现协作行为。</div></li></ul><div><span style="font-weight: bold;">三、优缺点</span></div><div><span style="font-weight: bold;">优点</span></div><ul><li><div><span style="font-weight: bold;">减少子类生成。</span>Mediator将原本分布于多个对象间的行为集中在一起。改变这些行为只需生成Mediator的子类即可，这样各个Colleague类可被复用。</div></li><li><div><span style="font-weight: bold;">将各Colleague解耦。</span>Mediator有利于各Colleague间的松耦合，你可以独立的该表和复用各Colleague类和Mediator类。</div></li><li><div><span style="font-weight: bold;">简化了对象协议。</span>用Mediator和各Colleague间的一对多交互来代替多对多交互。一对多的关系更易于理解、维护和扩展。将原本难以理解的网状结构转变为相对简单的星型结构。</div></li><li><div><span style="font-weight: bold;">对对象如何协作进行了抽象。</span>将中介作为一个独立的概念并将其封装在一个对象中，使你将注意力从对象各自本身的行为转移到它们之间的交互上来。这有助于弄清楚一个系统中的对象是如何交互的。由于把对象如何协作进行了抽象，将中介者作为一个独立的概念，并将其封装在一个对象中，这样关注的对象就从对象各自本身的行为转移到它们之间的交互上来，也就是站在一个更宏观的角度去看待系统。</div></li><li><div>通过将对象彼此解耦，可以增加对象的复用性。</div></li><li><div>通过将控制逻辑集中，可以简化系统维护。</div></li><li><div>可以让对象之间所传递的消息变得简单而且大幅减少。</div></li></ul><div><span style="font-weight: bold;">缺点</span></div><ul><li><div><span style="font-weight: bold;">使控制集中化。</span>中介者模式将交互的复杂性变为中介者的复杂性。因为中介者封装了协议，它可能变得比任一个Colleague都复杂。这可能使得中介者自身成为一个难于维护的庞然大物。如果设计不当，中介者对象会变得过于复杂。</div></li></ul><div><span style="font-weight: bold;">四、可能的改进</span></div><ul><li><div><a href="https://github.com/PhycheLiu/DesignPattern_Study-Test/tree/master/Java/src/com/company/mediator/sample01">通过注册的机制在中介者对象中动态的加入同事对象。</a>同事类可以在中介者模式当中进行注册，在注册的同时，也会被告知中介者对象。</div></li></ul><div><span style="font-weight: bold;">五、个人理解</span></div><ul><li><div>中介者模式比较简单，概念并不复杂，但一定注意不要滥用。</div></li><li><div>中介者模式在特定领域应用广泛。</div></li><li><div>可以参考SOA中的ESB理解，感觉ESB是改进版本的中介者模式。</div></li></ul><div><br clear="none"/></div><div><br clear="none"/></div><div><br clear="none"/></div><div><br/></div><div><br/></div></div><div><br/></div></span>
</div></body></html> 